﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

public class PlayerPrefsX
{
    private static byte[] byteBlock;
    private static int endianDiff1;
    private static int endianDiff2;
    private static int idx;

    private static float ConvertBytesToFloat(byte[] bytes)
    {
        ConvertFrom4Bytes(bytes);
        return BitConverter.ToSingle(byteBlock, 0);
    }

    private static int ConvertBytesToInt32(byte[] bytes)
    {
        ConvertFrom4Bytes(bytes);
        return BitConverter.ToInt32(byteBlock, 0);
    }

    private static void ConvertFloatToBytes(float f, byte[] bytes)
    {
        byteBlock = BitConverter.GetBytes(f);
        ConvertTo4Bytes(bytes);
    }

    private static void ConvertFrom4Bytes(byte[] bytes)
    {
        byteBlock[endianDiff1] = bytes[idx];
        byteBlock[1 + endianDiff2] = bytes[idx + 1];
        byteBlock[2 - endianDiff2] = bytes[idx + 2];
        byteBlock[3 - endianDiff1] = bytes[idx + 3];
        idx += 4;
    }

    private static void ConvertFromColor(Color[] array, byte[] bytes, int i)
    {
        ConvertFloatToBytes(array[i].r, bytes);
        ConvertFloatToBytes(array[i].g, bytes);
        ConvertFloatToBytes(array[i].b, bytes);
        ConvertFloatToBytes(array[i].a, bytes);
    }

    private static void ConvertFromFloat(float[] array, byte[] bytes, int i)
    {
        ConvertFloatToBytes(array[i], bytes);
    }

    private static void ConvertFromInt(int[] array, byte[] bytes, int i)
    {
        ConvertInt32ToBytes(array[i], bytes);
    }

    private static void ConvertFromQuaternion(Quaternion[] array, byte[] bytes, int i)
    {
        ConvertFloatToBytes(array[i].x, bytes);
        ConvertFloatToBytes(array[i].y, bytes);
        ConvertFloatToBytes(array[i].z, bytes);
        ConvertFloatToBytes(array[i].w, bytes);
    }

    private static void ConvertFromVector2(Vector2[] array, byte[] bytes, int i)
    {
        ConvertFloatToBytes(array[i].x, bytes);
        ConvertFloatToBytes(array[i].y, bytes);
    }

    private static void ConvertFromVector3(Vector3[] array, byte[] bytes, int i)
    {
        ConvertFloatToBytes(array[i].x, bytes);
        ConvertFloatToBytes(array[i].y, bytes);
        ConvertFloatToBytes(array[i].z, bytes);
    }

    private static void ConvertInt32ToBytes(int i, byte[] bytes)
    {
        byteBlock = BitConverter.GetBytes(i);
        ConvertTo4Bytes(bytes);
    }

    private static void ConvertTo4Bytes(byte[] bytes)
    {
        bytes[idx] = byteBlock[endianDiff1];
        bytes[idx + 1] = byteBlock[1 + endianDiff2];
        bytes[idx + 2] = byteBlock[2 - endianDiff2];
        bytes[idx + 3] = byteBlock[3 - endianDiff1];
        idx += 4;
    }

    private static void ConvertToColor(List<Color> list, byte[] bytes)
    {
        list.Add(new Color(ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes)));
    }

    private static void ConvertToFloat(List<float> list, byte[] bytes)
    {
        list.Add(ConvertBytesToFloat(bytes));
    }

    private static void ConvertToInt(List<int> list, byte[] bytes)
    {
        list.Add(ConvertBytesToInt32(bytes));
    }

    private static void ConvertToQuaternion(List<Quaternion> list, byte[] bytes)
    {
        list.Add(new Quaternion(ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes)));
    }

    private static void ConvertToVector2(List<Vector2> list, byte[] bytes)
    {
        list.Add(new Vector2(ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes)));
    }

    private static void ConvertToVector3(List<Vector3> list, byte[] bytes)
    {
        list.Add(new Vector3(ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes), ConvertBytesToFloat(bytes)));
    }

    public static bool GetBool(string name)
    {
        return (PlayerPrefs.GetInt(name) == 1);
    }

    public static bool GetBool(string name, bool defaultValue)
    {
        return (1 == PlayerPrefs.GetInt(name, !defaultValue ? 0 : 1));
    }

    public static bool[] GetBoolArray(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return new bool[0];
        }
        byte[] sourceArray = Convert.FromBase64String(PlayerPrefs.GetString(key));
        if (sourceArray.Length < 5)
        {
            Debug.LogError("Corrupt preference file for " + key);
            return new bool[0];
        }
        if (sourceArray[0] != 2)
        {
            Debug.LogError(key + " is not a boolean array");
            return new bool[0];
        }
        Initialize();
        byte[] destinationArray = new byte[sourceArray.Length - 5];
        Array.Copy(sourceArray, 5, destinationArray, 0, destinationArray.Length);
        BitArray array = new BitArray(destinationArray) {
            Length = ConvertBytesToInt32(sourceArray)
        };
        bool[] flagArray = new bool[array.Count];
        array.CopyTo(flagArray, 0);
        return flagArray;
    }

    public static bool[] GetBoolArray(string key, bool defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetBoolArray(key);
        }
        bool[] flagArray = new bool[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            flagArray[i] = defaultValue;
        }
        return flagArray;
    }

    public static Color GetColor(string key)
    {
        float[] floatArray = GetFloatArray(key);
        if (floatArray.Length < 4)
        {
            return new Color(0f, 0f, 0f, 0f);
        }
        return new Color(floatArray[0], floatArray[1], floatArray[2], floatArray[3]);
    }

    public static Color GetColor(string key, Color defaultValue)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetColor(key);
        }
        return defaultValue;
    }

    public static Color[] GetColorArray(string key)
    {
        List<Color> list = new List<Color>();
        GetValue<List<Color>>(key, list, ArrayType.Color, 4, new Action<List<Color>, byte[]>(PlayerPrefsX.ConvertToColor));
        return list.ToArray();
    }

    public static Color[] GetColorArray(string key, Color defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetColorArray(key);
        }
        Color[] colorArray = new Color[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            colorArray[i] = defaultValue;
        }
        return colorArray;
    }

    public static float[] GetFloatArray(string key)
    {
        List<float> list = new List<float>();
        GetValue<List<float>>(key, list, ArrayType.Float, 1, new Action<List<float>, byte[]>(PlayerPrefsX.ConvertToFloat));
        return list.ToArray();
    }

    public static float[] GetFloatArray(string key, float defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetFloatArray(key);
        }
        float[] numArray = new float[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            numArray[i] = defaultValue;
        }
        return numArray;
    }

    public static int[] GetIntArray(string key)
    {
        List<int> list = new List<int>();
        GetValue<List<int>>(key, list, ArrayType.Int32, 1, new Action<List<int>, byte[]>(PlayerPrefsX.ConvertToInt));
        return list.ToArray();
    }

    public static int[] GetIntArray(string key, int defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetIntArray(key);
        }
        int[] numArray = new int[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            numArray[i] = defaultValue;
        }
        return numArray;
    }

    public static long GetLong(string key)
    {
        int @int = PlayerPrefs.GetInt(key + "_lowBits");
        ulong num3 = (ulong) PlayerPrefs.GetInt(key + "_highBits");
        num3 = num3 << 0x20;
        return (long) (num3 | ((ulong) @int));
    }

    public static long GetLong(string key, long defaultValue)
    {
        int @int;
        int num2;
        SplitLong(defaultValue, out @int, out num2);
        @int = PlayerPrefs.GetInt(key + "_lowBits", @int);
        ulong num3 = (ulong) PlayerPrefs.GetInt(key + "_highBits", num2);
        num3 = num3 << 0x20;
        return (long) (num3 | ((ulong) @int));
    }

    public static Quaternion GetQuaternion(string key)
    {
        float[] floatArray = GetFloatArray(key);
        if (floatArray.Length < 4)
        {
            return Quaternion.identity;
        }
        return new Quaternion(floatArray[0], floatArray[1], floatArray[2], floatArray[3]);
    }

    public static Quaternion GetQuaternion(string key, Quaternion defaultValue)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetQuaternion(key);
        }
        return defaultValue;
    }

    public static Quaternion[] GetQuaternionArray(string key)
    {
        List<Quaternion> list = new List<Quaternion>();
        GetValue<List<Quaternion>>(key, list, ArrayType.Quaternion, 4, new Action<List<Quaternion>, byte[]>(PlayerPrefsX.ConvertToQuaternion));
        return list.ToArray();
    }

    public static Quaternion[] GetQuaternionArray(string key, Quaternion defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetQuaternionArray(key);
        }
        Quaternion[] quaternionArray = new Quaternion[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            quaternionArray[i] = defaultValue;
        }
        return quaternionArray;
    }

    public static string[] GetStringArray(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return new string[0];
        }
        string str = PlayerPrefs.GetString(key);
        int index = str.IndexOf("|"[0]);
        if (index < 4)
        {
            Debug.LogError("Corrupt preference file for " + key);
            return new string[0];
        }
        byte[] buffer = Convert.FromBase64String(str.Substring(0, index));
        if (buffer[0] != 3)
        {
            Debug.LogError(key + " is not a string array");
            return new string[0];
        }
        Initialize();
        int num2 = buffer.Length - 1;
        string[] strArray = new string[num2];
        int startIndex = index + 1;
        for (int i = 0; i < num2; i++)
        {
            int length = buffer[idx++];
            if ((startIndex + length) > str.Length)
            {
                Debug.LogError("Corrupt preference file for " + key);
                return new string[0];
            }
            strArray[i] = str.Substring(startIndex, length);
            startIndex += length;
        }
        return strArray;
    }

    public static string[] GetStringArray(string key, string defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetStringArray(key);
        }
        string[] strArray = new string[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            strArray[i] = defaultValue;
        }
        return strArray;
    }

    private static void GetValue<T>(string key, T list, ArrayType arrayType, int vectorNumber, Action<T, byte[]> convert) where T: IList
    {
        if (PlayerPrefs.HasKey(key))
        {
            byte[] buffer = Convert.FromBase64String(PlayerPrefs.GetString(key));
            if (((buffer.Length - 1) % (vectorNumber * 4)) != 0)
            {
                Debug.LogError("Corrupt preference file for " + key);
            }
            else if (((ArrayType) buffer[0]) != arrayType)
            {
                Debug.LogError(key + " is not a " + arrayType.ToString() + " array");
            }
            else
            {
                Initialize();
                int num = (buffer.Length - 1) / (vectorNumber * 4);
                for (int i = 0; i < num; i++)
                {
                    convert(list, buffer);
                }
            }
        }
    }

    private static Vector2 GetVector2(string key)
    {
        float[] floatArray = GetFloatArray(key);
        if (floatArray.Length < 2)
        {
            return Vector2.zero;
        }
        return new Vector2(floatArray[0], floatArray[1]);
    }

    public static Vector2 GetVector2(string key, Vector2 defaultValue)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetVector2(key);
        }
        return defaultValue;
    }

    public static Vector2[] GetVector2Array(string key)
    {
        List<Vector2> list = new List<Vector2>();
        GetValue<List<Vector2>>(key, list, ArrayType.Vector2, 2, new Action<List<Vector2>, byte[]>(PlayerPrefsX.ConvertToVector2));
        return list.ToArray();
    }

    public static Vector2[] GetVector2Array(string key, Vector2 defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetVector2Array(key);
        }
        Vector2[] vectorArray = new Vector2[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            vectorArray[i] = defaultValue;
        }
        return vectorArray;
    }

    public static Vector3 GetVector3(string key)
    {
        float[] floatArray = GetFloatArray(key);
        if (floatArray.Length < 3)
        {
            return Vector3.zero;
        }
        return new Vector3(floatArray[0], floatArray[1], floatArray[2]);
    }

    public static Vector3 GetVector3(string key, Vector3 defaultValue)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetVector3(key);
        }
        return defaultValue;
    }

    public static Vector3[] GetVector3Array(string key)
    {
        List<Vector3> list = new List<Vector3>();
        GetValue<List<Vector3>>(key, list, ArrayType.Vector3, 3, new Action<List<Vector3>, byte[]>(PlayerPrefsX.ConvertToVector3));
        return list.ToArray();
    }

    public static Vector3[] GetVector3Array(string key, Vector3 defaultValue, int defaultSize)
    {
        if (PlayerPrefs.HasKey(key))
        {
            return GetVector3Array(key);
        }
        Vector3[] vectorArray = new Vector3[defaultSize];
        for (int i = 0; i < defaultSize; i++)
        {
            vectorArray[i] = defaultValue;
        }
        return vectorArray;
    }

    private static void Initialize()
    {
        if (BitConverter.IsLittleEndian)
        {
            endianDiff1 = 0;
            endianDiff2 = 0;
        }
        else
        {
            endianDiff1 = 3;
            endianDiff2 = 1;
        }
        if (byteBlock == null)
        {
            byteBlock = new byte[4];
        }
        idx = 1;
    }

    private static bool SaveBytes(string key, byte[] bytes)
    {
        try
        {
            PlayerPrefs.SetString(key, Convert.ToBase64String(bytes));
        }
        catch
        {
            return false;
        }
        return true;
    }

    public static bool SetBool(string name, bool value)
    {
        try
        {
            PlayerPrefs.SetInt(name, !value ? 0 : 1);
        }
        catch
        {
            return false;
        }
        return true;
    }

    public static bool SetBoolArray(string key, bool[] boolArray)
    {
        byte[] array = new byte[((boolArray.Length + 7) / 8) + 5];
        array[0] = Convert.ToByte(ArrayType.Bool);
        new BitArray(boolArray).CopyTo(array, 5);
        Initialize();
        ConvertInt32ToBytes(boolArray.Length, array);
        return SaveBytes(key, array);
    }

    public static bool SetColor(string key, Color color)
    {
        float[] floatArray = new float[] { color.r, color.g, color.b, color.a };
        return SetFloatArray(key, floatArray);
    }

    public static bool SetColorArray(string key, Color[] colorArray)
    {
        return SetValue<Color[]>(key, colorArray, ArrayType.Color, 4, new Action<Color[], byte[], int>(PlayerPrefsX.ConvertFromColor));
    }

    public static bool SetFloatArray(string key, float[] floatArray)
    {
        return SetValue<float[]>(key, floatArray, ArrayType.Float, 1, new Action<float[], byte[], int>(PlayerPrefsX.ConvertFromFloat));
    }

    public static bool SetIntArray(string key, int[] intArray)
    {
        return SetValue<int[]>(key, intArray, ArrayType.Int32, 1, new Action<int[], byte[], int>(PlayerPrefsX.ConvertFromInt));
    }

    public static void SetLong(string key, long value)
    {
        int num;
        int num2;
        SplitLong(value, out num, out num2);
        PlayerPrefs.SetInt(key + "_lowBits", num);
        PlayerPrefs.SetInt(key + "_highBits", num2);
    }

    public static bool SetQuaternion(string key, Quaternion vector)
    {
        float[] floatArray = new float[] { vector.x, vector.y, vector.z, vector.w };
        return SetFloatArray(key, floatArray);
    }

    public static bool SetQuaternionArray(string key, Quaternion[] quaternionArray)
    {
        return SetValue<Quaternion[]>(key, quaternionArray, ArrayType.Quaternion, 4, new Action<Quaternion[], byte[], int>(PlayerPrefsX.ConvertFromQuaternion));
    }

    public static bool SetStringArray(string key, string[] stringArray)
    {
        byte[] inArray = new byte[stringArray.Length + 1];
        inArray[0] = Convert.ToByte(ArrayType.String);
        Initialize();
        for (int i = 0; i < stringArray.Length; i++)
        {
            if (stringArray[i] == null)
            {
                Debug.LogError("Can't save null entries in the string array when setting " + key);
                return false;
            }
            if (stringArray[i].Length > 0xff)
            {
                Debug.LogError("Strings cannot be longer than 255 characters when setting " + key);
                return false;
            }
            inArray[idx++] = (byte) stringArray[i].Length;
        }
        try
        {
            PlayerPrefs.SetString(key, Convert.ToBase64String(inArray) + "|" + string.Join(string.Empty, stringArray));
        }
        catch
        {
            return false;
        }
        return true;
    }

    private static bool SetValue<T>(string key, T array, ArrayType arrayType, int vectorNumber, Action<T, byte[], int> convert) where T: IList
    {
        byte[] buffer = new byte[((4 * array.Count) * vectorNumber) + 1];
        buffer[0] = Convert.ToByte(arrayType);
        Initialize();
        for (int i = 0; i < array.Count; i++)
        {
            convert(array, buffer, i);
        }
        return SaveBytes(key, buffer);
    }

    public static bool SetVector2(string key, Vector2 vector)
    {
        float[] floatArray = new float[] { vector.x, vector.y };
        return SetFloatArray(key, floatArray);
    }

    public static bool SetVector2Array(string key, Vector2[] vector2Array)
    {
        return SetValue<Vector2[]>(key, vector2Array, ArrayType.Vector2, 2, new Action<Vector2[], byte[], int>(PlayerPrefsX.ConvertFromVector2));
    }

    public static bool SetVector3(string key, Vector3 vector)
    {
        float[] floatArray = new float[] { vector.x, vector.y, vector.z };
        return SetFloatArray(key, floatArray);
    }

    public static bool SetVector3Array(string key, Vector3[] vector3Array)
    {
        return SetValue<Vector3[]>(key, vector3Array, ArrayType.Vector3, 3, new Action<Vector3[], byte[], int>(PlayerPrefsX.ConvertFromVector3));
    }

    public static void ShowArrayType(string key)
    {
        byte[] buffer = Convert.FromBase64String(PlayerPrefs.GetString(key));
        if (buffer.Length > 0)
        {
            Debug.Log(key + " is a " + ((ArrayType) buffer[0]).ToString() + " array");
        }
    }

    private static void SplitLong(long input, out int lowBits, out int highBits)
    {
        lowBits = (int) ((uint) input);
        highBits = (int) ((uint) (input >> 0x20));
    }

    private enum ArrayType
    {
        Float,
        Int32,
        Bool,
        String,
        Vector2,
        Vector3,
        Quaternion,
        Color
    }
}

